Syntax10.Scn.Fnt Syntax10i.Scn.Fnt StampElems Alloc 2 Feb 95 Syntax10b.Scn.Fnt MODULE DialogFrames; (** extended version Markus Knasm ller 25.May.94 - IMPORT Dialogs, Display, Files, Input, MenuViewers, Oberon, TextFrames, Texts, Viewers; CONST bkCol = 13; menu = "System.Close System.Copy System.Grow"; gridMax* = 100; gridMin* = 1; TYPE Frame* = POINTER TO FrameDesc; FrameDesc* = RECORD(Display.FrameDesc) col*: INTEGER; (** background-color of the frame *) panel*: Dialogs.Panel; (** panel displayed in this frame *) grid*: INTEGER; (** grid of the frame *) pat*: Display.Pattern; (** background-pattern *) END; GetFrameMsg* = RECORD(Display.FrameMsg) p*: Dialogs.Panel; f*: Frame; END; SetCaretMsg = RECORD(Display.FrameMsg) p: Dialogs.Panel; x, y: INTEGER; END; w0: Texts.Writer; left, right, top, bot: INTEGER; PROCEDURE Min (x, y: INTEGER): INTEGER; BEGIN IF x < y THEN RETURN x ELSE RETURN y END END Min; PROCEDURE (f: Frame) MarkMenu; (* see TextFrames *) VAR r: Texts.Reader; v: Viewers.Viewer; t: Texts.Text; ch: CHAR; BEGIN v := Viewers.This (f.X, f.Y); IF (v IS MenuViewers.Viewer) & (v.dsc IS TextFrames.Frame) & (f # v.dsc) THEN t := v.dsc(TextFrames.Frame).text; IF t.len > 0 THEN Texts.OpenReader(r, t, t.len - 1); Texts.Read(r, ch) ELSE ch := 0X END; IF ch # "!" THEN Texts.Write(w0, "!"); Texts.Append(t, w0.buf) END END; END MarkMenu; PROCEDURE (f: Frame) Restore*; (** restores the frame *) BEGIN Oberon.RemoveMarks (f.X, f.Y, f.W, f.H); IF f.pat # MAX (INTEGER) THEN Display.ReplPatternC (f, f.col, f.pat, f.X, f.Y, f.W, f.H, f.X, f.Y, Display.replace) ELSE Display.ReplConstC (f, f.col, f.X, f.Y, f.W, f.H, Display.replace) END; f.panel.Draw (f.X, f.Y + f.H, f) END Restore; PROCEDURE (f: Frame) DrawObject (o: Dialogs.Object; drawmode: BOOLEAN); (* drawmode = TRUE => Draw drawmode = FALSE => Delete *) VAR x, y, ox, oy, ow, oh: INTEGER; i: LONGINT; BEGIN o.GetDim (ox, oy, ow, oh); x := f.X + ox; y := f.Y + f.H + oy; Oberon.RemoveMarks (x, y, ow, oh); IF (~ drawmode) THEN Display.ReplConstC (f, f.col, x, y, ow, oh, Display.paint); IF f.pat # MAX (INTEGER) THEN Display.ReplPatternC (f, f.col, f.pat, x, y, ow, oh, f.X, f.Y, Display.replace) END ELSE o.Draw (x, y, f) END END DrawObject; PROCEDURE (f: Frame) TrackMouse (x, y: INTEGER; keys: SET); BEGIN Oberon.DrawCursor (Oberon.Mouse, Oberon.Arrow, x, y); WHILE keys # {} DO Input.Mouse (keys, x, y); Oberon.DrawCursor (Oberon.Mouse, Oberon.Arrow, x, y); END END TrackMouse; PROCEDURE (f: Frame) Send (x, y: INTEGER; VAR m: Display.FrameMsg; VAR cond: BOOLEAN); VAR o: Dialogs.Object; BEGIN o := f.panel.ThisObject (x - f.X, y - f.Y - f.H); IF o # NIL THEN o.Handle (f, m); cond := TRUE ELSE cond := FALSE END END Send; PROCEDURE (f: Frame) Extend (newY: INTEGER); VAR dY, newH: INTEGER; BEGIN dY := f.Y - newY; IF f.pat # MAX (INTEGER) THEN Display.ReplPattern (f.col, f.pat, f.X, newY, f.W, f.Y - newY, Display.replace) ELSE Display.ReplConst (f.col, f.X, newY, f.W, f.Y - newY, Display.replace) END; f.H := f.H + f.Y - newY; f.Y := newY; f.panel.Draw (f.X, f.Y + f.H, f) END Extend; PROCEDURE (f: Frame) Reduce (newY: INTEGER); BEGIN f.H := f.H + f.Y - newY; f.Y := newY END Reduce; PROCEDURE (f: Frame) Modify (id, dY, y, h: INTEGER); BEGIN Oberon.RemoveMarks(f.X, f.Y, f.W, f.H); f.panel.RemoveSelections; IF id = MenuViewers.extend THEN IF dY > 0 THEN IF f.pat # MAX (INTEGER) THEN Display.ReplPattern (f.col, f.pat, f.X, f.Y + dY, f.W, f.H, Display.replace) ELSE Display.ReplConst (f.col, f.X, f.Y + dY, f.W, f.H, Display.replace) END; INC (f.Y, dY) END; f.Extend (y) ELSIF id = MenuViewers.reduce THEN f.Reduce (y + dY); IF dY > 0 THEN Display.CopyBlock(f.X, f.Y, f.W, f.H, f.X, y, Display.replace); f.Y := y END END END Modify; PROCEDURE Handle* (f: Display.Frame; VAR m: Display.FrameMsg); (** handles the message m sent to frame f *) VAR cond: BOOLEAN; copy: Frame; PROCEDURE IsIn (f: Display.Frame; x, y: INTEGER): BOOLEAN; BEGIN IF (x >= f.X) & (x <= f.X + f.W) & (y > f.Y) & (y <= f.Y + f.H) THEN RETURN TRUE ELSE RETURN FALSE END END IsIn; BEGIN WITH f: Frame DO WITH m: Oberon.InputMsg DO IF m.id = Oberon.track THEN IF IsIn (f, m.X, m.Y) THEN f.Send (m.X, m.Y, m, cond); (* sends it to object *) IF ~ cond THEN f.TrackMouse (m.X, m.Y, m.keys) (* draws cursor if there is no object *) END END ELSE f.panel.Broadcast (f, m) END | m: MenuViewers.ModifyMsg DO f.Modify (m.id, m.dY, m.Y, m.H); f.panel.Broadcast (f, m) | m: Oberon.CopyMsg DO NEW (copy); copy^ := f^; m.F := copy; | m: Dialogs.NotifyMsg DO IF m.id = 0 THEN IF f.panel.Contains (m.obj) THEN f.DrawObject (m.obj, TRUE) END ELSIF m.id = 1 THEN IF f.panel.Contains (m.obj) THEN f.DrawObject (m.obj, FALSE) END ELSIF m.id = 2 THEN IF m.p = f.panel THEN f.MarkMenu END ELSIF m.id = 3 THEN IF m.p = f.panel THEN f.Restore END END | m: SetCaretMsg DO IF m.p = f.panel THEN Oberon.RemoveMarks (f.X, f.Y, f.W, f.H); Oberon.Pointer.X := m.x + f.X; Oberon.Pointer.Y := m.y + f.Y + f.H; END | m: GetFrameMsg DO IF f.panel = m.p THEN m.f := f END ELSE f.panel.Broadcast (f, m) (* sends it to all objects in the panel *) END END END Handle; PROCEDURE (f: Frame) Open* (handle: Display.Handler; p: Dialogs.Panel); (** opens the frame f with the handler handle and the panel p *) BEGIN f.handle := handle; f.panel := p; f.col := bkCol; f.grid := 1; f.pat := MAX (INTEGER) END Open; PROCEDURE GetCaretPosition* (VAR p: Dialogs.Panel; VAR xpos, ypos: INTEGER); (** returns the panel p and the positin (xpos, ypos) of the caret *) VAR x, y: INTEGER; f: Frame; v: Viewers.Viewer; BEGIN x := Oberon.Pointer.X; y := Oberon.Pointer.Y; v := Viewers.This (x, y); IF (v.dsc # NIL) & (v.dsc.next # NIL) & (v.dsc.next IS Frame) THEN f := v.dsc.next(Frame); p := f.panel; xpos := x - f.X; ypos := y - f.Y - f.H ELSE p := NIL END END GetCaretPosition; PROCEDURE box (obj: Dialogs.Object; VAR done: BOOLEAN); VAR x, y, w, h: INTEGER; BEGIN obj.GetDim (x, y, w, h); IF x < left THEN left := x END; IF y < bot THEN bot := y END; IF x + w > right THEN right := x + w END; IF y + h > top THEN top := y + h END END box; PROCEDURE OpenPanel* (name: ARRAY OF CHAR; x, y: INTEGER; VAR p: Dialogs.Panel); (** reads a panel p from file name and opens a viewer at x, y showing that panel *) VAR f: Frame; file: Files.File; r: Files.Rider; h, res: INTEGER; v, vmax: Viewers.Viewer; m: TextFrames.Frame; t: Texts.Text; buf: Texts.Buffer; BEGIN file := Files.Old (name); NEW (p); IF file # NIL THEN Files.Set (r, file, 0); p.Load (r) END; NEW (f); f.Open (Handle, p); v := Viewers.This (x, 0); vmax := NIL; h := 0; WHILE v.state > 1 DO IF v.H > h THEN vmax := v; h := v.H END; v := Viewers.Next (v) END; IF vmax # NIL THEN left := MAX (INTEGER); right := MIN (INTEGER); bot := MAX (INTEGER); top := MIN (INTEGER); p.Enumerate (box); y := Min (vmax.Y + ABS (bot) + 10 + TextFrames.menuH, vmax.Y + vmax.H - TextFrames.menuH - 2) END; IF Files.Old ("Dialog.Menu.Text") = NIL THEN m := TextFrames.NewMenu (name, menu) ELSE m := TextFrames.NewMenu (name, ""); NEW (t); Texts.Open (t, "Dialog.Menu.Text"); NEW (buf); Texts.OpenBuf (buf); Texts.Save (t, 0, t.len, buf); Texts.Append (m.text, buf) END; v := MenuViewers.New (m, f, TextFrames.menuH, x, y); IF p.cmd[0] # 0X THEN Dialogs.cmdPanel := p; Oberon.Call (p.cmd, Oberon.Par, FALSE, res) END; END OpenPanel; PROCEDURE FindObject* (VAR o: Dialogs.Object; VAR p: Dialogs.Panel); (** returns the object o below the caret and the panel p containing it *) VAR x, y: INTEGER; BEGIN GetCaretPosition (p, x, y); IF p # NIL THEN o := p.ThisObject (x, y); IF o # NIL THEN Dialogs.res := Dialogs.ok ELSE Dialogs.res := Dialogs.objectNotFound END ELSE Dialogs.res := Dialogs.noPanelSelected END END FindObject; PROCEDURE SetCaretAtObject* (o: Dialogs.Object); (** sets the caret in a way that the object o is below the caret *) VAR msg: SetCaretMsg; x, y, w, h: INTEGER; BEGIN o.GetDim (x, y, w, h); msg.p := o.panel; msg.x := x; msg.y := y; Viewers.Broadcast (msg) END SetCaretAtObject; BEGIN Texts.OpenWriter (w0) END DialogFrames.